# coding=utf8
# 全世界最帅的帅哥
from collections import deque
from comment.modules.funding_not_matched import FundingNotMatched
from sqlalchemy import or_
from flask import current_app
from comment.modules.debt_info import DebtInfo
from comment.modules import db
from comment.modules.matched_result import MatchedResult
from .const import DealType
from comment.utils.gen_trans_id import generate_trans_id
from datetime import datetime
from comment.modules.expected_return import ExpectedReturn
from dateutil.relativedelta import relativedelta
from flask_restful import Resource
from comment.modules.account import Account


class MatchQueue:

    def __init__(self, item_list):
        # 初始化栈
        # 只用双端队列的一端
        self.items = deque(item_list)

    # 从栈中取一个待匹配的数据
    def get_item(self):
        return self.items.popleft()

    # 将一个即将待匹配的数据放入栈中
    def push(self, item):
        self.items.appendleft(item)
        return

    # 判断栈中的数据是否为空
    @property
    def is_empty(self):
        return len(self.items) == 0


class Match:
    # 正式开始撮合匹配资金
    def __init__(self):
        # 把所有待匹配的债券和待匹配的资金都从数据库中取出来
        # 查询没有完全匹配的债券列表
        debt_list = DebtInfo.query.filter(or_(DebtInfo.matchedStatus == 0, DebtInfo.matchedStatus == 1)).order_by(
            DebtInfo.id).all()
        self.debt_deque = MatchQueue(debt_list)  # 待匹配的债券

        # 查询未匹配的资金列表
        fund_list = FundingNotMatched.query.filter(
            or_(FundingNotMatched.matchedStatus == 0, FundingNotMatched.matchedStatus == 1)).order_by(
            FundingNotMatched.fId).all()
        self.funds_deque = MatchQueue(fund_list)

    def start_match(self):
        # 正式开始撮合匹配
        try:
            debt_item, funds_item = None, None
            # 从债券队列和资金队列中取值
            while not self.debt_deque.is_empty and not self.funds_deque.is_empty:
                debt_item = self.debt_deque.get_item()
                funds_item = self.funds_deque.get_item()

                if debt_item.debtMoney > funds_item.fNotMatchedMoney:
                    self.debtMoneyMoreThanFunds(debt_item, funds_item)
                elif debt_item.debtMoney == funds_item.fNotMatchedMoney:
                    self.debtMoneyEqualFunds(debt_item, funds_item)
                else:
                    self.debtMoneyLessThanFunds(debt_item, funds_item)

                db.session.commit()
                return {"msg": "撮合匹配成功！"}
            if not debt_item or not funds_item:
                return {"message": "当前债券或者资金不足"}

        except Exception as e:
            current_app.logger.error(e)
            db.session.rollback()
            return {"message": "服务器忙，请稍后重试"}

    def debtMoneyMoreThanFunds(self, debt, funds):
        # 新增一条匹配结果
        self.createMatchedResult(debt, funds, funds.fNotMatchedMoney, False)
        # 修改债券的状态
        debt.debtMoney -= funds.fNotMatchedMoney  # 剩余的债券金额
        debt.matchedStatus = 1  # 部分匹配
        debt.matchedMoney += funds.fNotMatchedMoney  # 已匹配金额

        # 修改资金的状态
        funds.fNotMatchedMoney = 0  # 债券大于funds 匹配金额清空
        funds.matchedStatus = 2  # 改变funds状态

        # 债券还剩一下一部分没有匹配完全，接着插入到栈中
        self.debt_deque.push(debt)

        # 投资理财的金额全部匹配完了，所以开始产生收益
        self.createExpectedResult(funds)

    def debtMoneyLessThanFunds(self, debt, funds):
        # 新增一条匹配结构
        self.createMatchedResult(debt, funds, debt.debtMoney, True)  # 债券金额全部匹配完
        # 修改债券的状态
        debt.matchedStatus = 2  # 完全匹配
        debt.matchedMoney += debt.debtMoney  # 已匹配金额
        # 借款人的资金增加
        account = Account.query.filter(Account.userId == debt.user.id).first()
        account.balance += debt.repaymentMoney
        # 修改资金的状态
        funds.fNotMatchedMoney -= debt.debtMoney  # 债券大于funds 匹配金额清空
        funds.matchedStatus = 1  # 部分匹配
        debt.debtMoney = 0  # 剩余的债券金额
        # 正式开始还款计划
        self.startRepayPlan(debt)
        # 资金还有一部分没有完全匹配，接着插入到栈中
        self.funds_deque.push(funds)

    def startRepayPlan(self, debt):
        # 还款计划开始生效，修改数据库中的还款计划
        repay_list = debt.debtor_record
        for repay in repay_list:
            repay.receivableDate = datetime.now() + relativedelta(months=repay.currentTerm)

    def debtMoneyEqualFunds(self, debt, funds):
        # 新增一条匹配结构
        self.createMatchedResult(debt, funds, debt.debtMoney, True)  # 债券金额全部匹配完
        # 修改债券的状态
        debt.matchedStatus = 2  # 完全匹配
        debt.matchedMoney += debt.debtMoney  # 已匹配金额
        # 借款人的资金增加
        debt.user.accountInfo.balance += debt.repaymentMoney
        debt.debtMoney = 0  # 剩余的债券金额
        # 修改资金的状态
        funds.fNotMatchedMoney = 0  # 债券大于funds 匹配金额清空
        funds.matchedStatus = 2  # 完全匹配
        # 正式开始还款计划
        self.startRepayPlan(debt)
        # 正式开始还款计划
        self.startRepayPlan(debt)

    def createMatchedResult(self, debt, funds, matched_money, is_dept):
        # 创建匹配流水号
        match_num = generate_trans_id(DealType.match.name)
        # 获得user_id
        user_id = debt.borrowerId if is_dept else funds.investRecord.pUid
        # 创建一条匹配结果数据
        match_result = MatchedResult(userId=user_id, debtId=debt.id, investId=funds.fId,
                                     transferSerialNo=match_num, purchaseMoney=matched_money,
                                     confirmedDate=funds.investRecord.pDate, isConfirmed=1, matchDate=datetime.now())
        db.session.add(match_result)

    def createExpectedResult(self, funds):
        earnings = ExpectedReturn(userId=funds.investRecord.pUid, productId=funds.investRecord.pProductId,
                                  investRecord=funds.investRecord.pId,
                                  expectedDate=datetime.now() + relativedelta(months=funds.investRecord.pDeadline),
                                  expectedMoney=funds.investRecord.pProspectiveEarnings)
        # 修改投资记录的状态
        funds.investRecord.pStatus = 1
        # 修改 投资记录开始计算利息的时间
        funds.investRecord.pInterestStartDate = datetime.now()
        db.session.add(earnings)


class MatchUp(Resource):

    def post(self):
        match = Match()
        return match.start_match()
